Module('Phosphor.Events', function () {
    var Promise = this.Promise = function () { };

    Promise.prototype = Object.create( this.EventEmitter.prototype );
    Promise.prototype.succeed = function (value) {
        return this.resolve(value, true);
    };

    Promise.prototype.fail = function () {
        return this.resolve(null, false);
    };

    Promise.prototype.resolve = function (value, succeeded) {
        if (this.isResolved()) return this;

        this._resolved = true;
        this._succeeded = succeeded;

        if (succeeded) this.setValue(value);

        this.emit('resolved', value, succeeded);

        if (succeeded) {
            this.emit('succeeded', value);
        } else {
            this.emit('failed');
        }

        return this;
    };

    Promise.prototype.call = function (callback) {
        var fail, succeed, promise = this;
        fail = function () {
            promise.fail();
        };

        succeed = function () {
            promise.succeed();
        };

        callback.call(this, fail, succeed);

        return this;
    };

    Promise.prototype.when = // for dojo/jquery similarity
    Promise.prototype.then = function (callback, failure_callback) {
        var promise = new Promise();

        this.on('resolved', function (value, succeeded) {
            if (succeeded) {
                promise.succeed(callback(value));
            } else {
                if (failure_callback) { failure_callback(); }
                promise.fail();
            }
        });

        return promise;
    };

    Promise.prototype.getValue = function () { return this._value; };
    Promise.prototype.setValue = function (val) { return (this._value = val); };
    Promise.prototype.isResolved = function () { return !!this._resolved; };

    Promise.prototype.succeeded = function () { return !!this._succeeded; };
    Promise.prototype.failed = function () { return !this._succeeded; };

    Promise.getValue = function (promise) {
        return promise instanceof Promise ? promise.getValue() : promise;
    };

    Promise.isResolved = function (promise) {
        return promise instanceof Promise ? promise.isResolved() : true;
    };

    Promise.succeeded = function  (promise) {
        return promise instanceof Promise ? promise.succeeded() : true;
    };

    Promise.failed = function (promise) {
        return !Promise.succeeded(promise);
    };

    Promise.when = function () {
        var promises = [].slice.call(arguments, 0, -1);
        var callback = arguments[arguments.length - 1];

        return Promise.Array(promises, function (values) {
            return callback.apply(null, values);
        }); 
    };

    Promise.Array = function (promises, callback, ctx) {
        var promise = new Promise(),
            max = promise.length,
            i, check;

        callback = callback || function (i) { return i; };
        ctx      = ctx || null;

        check = function (success, value) {
            if (success) {
                promise.emit('progress', value);
            } else {
                promise.emit('error');
            }

            var values = [];

            for (i = 0; i < max; i++) {
                if (!Promise.isResolved(promises[i])) {
                    return false;
                }

                values[i] = Promise.getValue(promises[i]);
            }

            promise.succeed(callback.call(ctx, values));
            return true;
        };

        if (check()) return promise;

        for (i = 0; i < max; i++) {
            if (promises[i] instanceof Promise) {
                promises[i].on('resolved', check);
            }
        }

        return promise;
    };

    Promise.from = function (callback) {
        var promise = new Promise(),
            succeed = promise.succeed.bind(promise),
            fail = promise.fail.bind(promise);

        callback(succeed, fail);

        return promise;
    };
});
